﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Iit.ITBI.MDSManagerPOC.Microsoft.MasterDataServices;
using Iit.ITBI.MDSSql;
using System.Data;
using System.Data.SqlClient;


namespace Iit.ITBI.MDSManagerPOC
{
    class MDSManager
    {
        private ServiceClient service;
        private International international;


        public MDSManager()
        {
            this.service = new ServiceClient("WSHttpBinding_IService");
            this.international = new International();
        }
        public MDSManager(string Binding)
        {
            this.service = new ServiceClient(Binding);
            this.international = new International();
        }




        //private void CopyEntity(Identifier newModelId, Identifier versionId, Entity EntityToCopy)
        private void CopyEntity(Identifier newModelId, Entity EntityToCopy)
        {
            OperationResult or = new OperationResult();

            
                
            //Common.MDS_WS mds = new MDS_WS();
            //create a new guid for the new entity (target entity must NOT have the same ID than the source entity)             
            Guid newEntityId = Guid.NewGuid();

            //create a new metadata instance      
            Metadata md = new Metadata();
            md.Entities = new Entity[1];

            //add a new entity in this new metadata, with values and fields from source entity
            md.Entities[0] = new Entity()
            {
                Identifier = new ModelContextIdentifier() { ModelId = newModelId, Name = EntityToCopy.Identifier.Name, Id = newEntityId },
                AuditInfo = EntityToCopy.AuditInfo,
                ExtensionData = EntityToCopy.ExtensionData,
                ExplicitHierarchies = EntityToCopy.ExplicitHierarchies,
                IsBase = EntityToCopy.IsBase,
                IsFlat = EntityToCopy.IsFlat,
                IsSystem = EntityToCopy.IsSystem
            };

            Metadata retMd;

            //publish this new entity if it is not existing
            if (GetEntity(newModelId, EntityToCopy.Identifier.Name) == null)
            {
                retMd  = service.MetadataCreate(new International(), md, true, out or);
            }
            else
            {
                retMd = GetEntityMetadata(GetEntity(newModelId, EntityToCopy.Identifier.Name).Identifier);
            }
            
            ////get source entity attributes
            MetadataResultOptions SourceEntityAttributeResultOptions = new MetadataResultOptions();
            MetadataSearchCriteria SourceEntityAttributeSearchCriteria = new MetadataSearchCriteria();
            
            SourceEntityAttributeResultOptions.Attributes = ResultType.Details;
            SourceEntityAttributeSearchCriteria.SearchOption = SearchOption.UserDefinedObjectsOnly;
            SourceEntityAttributeSearchCriteria.Entities =  new Identifier[1] {EntityToCopy.Identifier};

            md = service.MetadataGet(international, SourceEntityAttributeResultOptions, SourceEntityAttributeSearchCriteria, out or);
                                /*new International(), 
                                 ref or,
                                 GetModel("Cross Model POC Master"), 
                                 GetEntity(GetModel("Cross Model POC Master"), "Colors").Identifier, 
                                 MDS_WS.MDAction.AttributesDetails);*/

            //create a new metadata instance for attributes to copy
            Metadata newMD = new Metadata();
            newMD.Attributes = new MetadataAttribute[md.Attributes.Length];

            int i = 0;

            //for each source entity attribute, create a new attribute containing values and fields from this source entity
            foreach (MetadataAttribute oldMA in md.Attributes)
            {
                MetadataAttribute ma = new MetadataAttribute()
                {
                    AttributeType = oldMA.AttributeType,
                    Identifier = new MemberTypeContextIdentifier()
                    {
                        //entityId is coming from the target entity                               
                        EntityId = retMd.Entities.First().Identifier,
                        //Id  is coming from the target entity
                        Id = retMd.Entities.First().Identifier.Id,
                        //internal Id  is coming from the target entity                             
                        InternalId = retMd.Entities.First().Identifier.InternalId,
                        ModelId = newModelId,
                        MemberType = oldMA.Identifier.MemberType,
                        Name = oldMA.Identifier.Name
                    },
                    DataType = oldMA.DataType,
                    DataTypeInformation = oldMA.DataTypeInformation,
                    AuditInfo = oldMA.AuditInfo,
                    ChangeTrackingGroup = oldMA.ChangeTrackingGroup,
                    DisplayWidth = oldMA.DisplayWidth,
                    ExtensionData = oldMA.ExtensionData,

                    InputMaskId = oldMA.InputMaskId,
                    IsCode = oldMA.IsCode,
                    IsName = oldMA.IsName,
                    IsReadOnly = oldMA.IsReadOnly,
                    IsSystem = oldMA.IsSystem,
                    Permission = oldMA.Permission,
                    SortOrder = oldMA.SortOrder

                };

                //add all destination attributes to the metadata
                newMD.Attributes[i++] = ma;

               // service.EntityMembersGet(international

                //service.EntityMembersMerge(international,null,true,or);

                //service.AttributeChange()

                
            }

            Console.WriteLine(newMD.Equals(md).ToString());

            //create the attributes metadata
            service.MetadataCreate(new International(), newMD, true, out or);

            //service.MetadataUpdate(new International(), AttributesToCreateMetaData);

            

            
        }


        

        //private void CopyEntity(Identifier newModelId, Identifier versionId, Entity EntityToCopy)
        private void CopyEntity(MasterToSlaveMapping m2s)
        {

            OperationResult or = new OperationResult();
            
            //create MDS objects from mapping metadata
            Model MasterModel = GetModel(m2s.MasterEntity.Model.Name);
            Model SlaveModel = GetModel(m2s.SlaveEntity.Model.Name);
            Entity MasterEntity = GetEntity(MasterModel, m2s.MasterEntity.Name);
                   
            //create a new metadata instance      
            Metadata EntityToCreateMetaData = new Metadata();
            EntityToCreateMetaData.Entities = new Entity[1];

            //add a new entity in this new metadata, with values and fields from source entity
            EntityToCreateMetaData.Entities[0] = new Entity()
            {
                Identifier = new ModelContextIdentifier() { ModelId = SlaveModel.Identifier, Name = m2s.SlaveEntity.Name, Id = m2s.SlaveEntity.MUID },
                AuditInfo = MasterEntity.AuditInfo,
                ExtensionData = MasterEntity.ExtensionData,
                ExplicitHierarchies = MasterEntity.ExplicitHierarchies,
                IsBase = MasterEntity.IsBase,
                IsFlat = MasterEntity.IsFlat,
                IsSystem = MasterEntity.IsSystem
            };

            Metadata NewlyCreatedEntityMetadata;

            NewlyCreatedEntityMetadata = service.MetadataCreate(new International(), EntityToCreateMetaData, true, out or);
            
            ////get source entity attributes
            MetadataResultOptions MasterEntityAttributeResultOptions = new MetadataResultOptions();
            MetadataSearchCriteria MasterEntityAttributeSearchCriteria = new MetadataSearchCriteria();

            MasterEntityAttributeResultOptions.Attributes = ResultType.Details;
            MasterEntityAttributeSearchCriteria.SearchOption = SearchOption.UserDefinedObjectsOnly;
            MasterEntityAttributeSearchCriteria.Entities = new Identifier[1] { MasterEntity.Identifier };

            EntityToCreateMetaData = service.MetadataGet(international, MasterEntityAttributeResultOptions, MasterEntityAttributeSearchCriteria, out or);
            /*new International(), 
             ref or,
             GetModel("Cross Model POC Master"), 
             GetEntity(GetModel("Cross Model POC Master"), "Colors").Identifier, 
             MDS_WS.MDAction.AttributesDetails);*/

            //create a new metadata instance for attributes to copy
            Metadata AttributesToCreateMetaData = new Metadata();
            AttributesToCreateMetaData.Attributes = new MetadataAttribute[EntityToCreateMetaData.Attributes.Length];

            int i = 0;

            //for each source entity attribute, create a new attribute containing values and fields from this source entity
            foreach (MetadataAttribute oldMA in EntityToCreateMetaData.Attributes)
            {
                MetadataAttribute ma = new MetadataAttribute()
                {
                    AttributeType = oldMA.AttributeType,
                    Identifier = new MemberTypeContextIdentifier()
                    {
                        //entityId is coming from the target entity                               
                        EntityId = NewlyCreatedEntityMetadata.Entities.First().Identifier,
                        //Id  is coming from the target entity
                        Id = NewlyCreatedEntityMetadata.Entities.First().Identifier.Id,
                        //internal Id  is coming from the target entity                             
                        InternalId = NewlyCreatedEntityMetadata.Entities.First().Identifier.InternalId,
                        ModelId = SlaveModel.Identifier,
                        MemberType = oldMA.Identifier.MemberType,
                        Name = oldMA.Identifier.Name
                    },
                    DataType = oldMA.DataType,
                    DataTypeInformation = oldMA.DataTypeInformation,
                    AuditInfo = oldMA.AuditInfo,
                    ChangeTrackingGroup = oldMA.ChangeTrackingGroup,
                    DisplayWidth = oldMA.DisplayWidth,
                    ExtensionData = oldMA.ExtensionData,

                    InputMaskId = oldMA.InputMaskId,
                    IsCode = oldMA.IsCode,
                    IsName = oldMA.IsName,
                    IsReadOnly = oldMA.IsReadOnly,
                    IsSystem = oldMA.IsSystem,
                    Permission = oldMA.Permission,
                    SortOrder = oldMA.SortOrder

                };

                //add all destination attributes to the metadata
                AttributesToCreateMetaData.Attributes[i++] = ma;

            }

            Console.WriteLine(AttributesToCreateMetaData.Equals(EntityToCreateMetaData).ToString());

            //create the attributes metadata
            service.MetadataCreate(new International(), AttributesToCreateMetaData, true, out or);
            
        }


        public void DoSomething()
        {


            //MDSSqlWrapper MDSSql = new MDSSqlWrapper(@"Server=SAXODKDEV7018\RAFADEV;Database=MDS_2012_2012;Trusted_Connection=True;");

            MDSMetaData MetaDataCache = new MDSMetaData(@"Server=SAXODKDEV7018\RAFADEV;Database=MDS_2012_2012;Trusted_Connection=True;");
            
            MetaDataCache.PopulateMasterToSlaveMappings();

            foreach (MasterToSlaveMapping m2s in MetaDataCache.MasterToSlaveMappings)
            { 
                if (m2s.SlaveEntity.Exists != true)
                {
                    Console.WriteLine("Copy Entity {0} from model {1} to model {2}",m2s.MasterEntity.Name, m2s.MasterEntity.Model.Name, m2s.SlaveEntity.Name);

                    CopyEntity(m2s);
                
                }
            
            }



            int i = 0;

            Console.ReadLine();

            return;

            //Model m = GetModel("Cross Model POC Master");
            //Console.WriteLine("Model Code: {0}, Name: {1}", m.Identifier.Id, m.Identifier.Name);

            //ListEntities(m);

            //m = GetModel("Cross Model POC Slave");
            //Console.WriteLine("Model Code: {0}, Name: {1}", m.Identifier.Id, m.Identifier.Name);

            //ListEntities(m);
            
            //Console.WriteLine("Now copy Color Entity");
            //CopyEntity(GetModel("Cross Model POC Slave").Identifier, GetEntity(GetModel("Cross Model POC Master"),"Colors"));
            //Console.WriteLine("after copy Color Entity");

            //m = GetModel("Cross Model POC Master");
            //Console.WriteLine("Model Code: {0}, Name: {1}", m.Identifier.Id, m.Identifier.Name);

            //ListEntities(m);

            //m = GetModel("Cross Model POC Slave");
            //Console.WriteLine("Model Code: {0}, Name: {1}", m.Identifier.Id, m.Identifier.Name);
        
        }

        void CopyEntity()
        {

            MetadataResultOptions ResultOptions = new MetadataResultOptions();
            MetadataSearchCriteria SearchCriteria = new MetadataSearchCriteria();
            OperationResult SearchResult;

            Identifier[] i;
            i = new Identifier[1];

            i.SetValue(GetEntity(GetModel("Cross Model POC Master"), "Colors").Identifier, 0);
            SearchCriteria.Entities = i;

            SearchCriteria.SearchOption = SearchOption.BothUserDefinedAndSystemObjects;
            
            Metadata EntityMetadata = service.MetadataGet(international, ResultOptions, SearchCriteria, out SearchResult);

            OperationResult EntityCloneResult;
            EntityCloneResult = service.MetadataClone(international, EntityMetadata);

            

            //service.MetadataCreate(
            


        }

        Model GetModel(string ModelName)
        {

            MetadataResultOptions ModelsResultOptions = new MetadataResultOptions();
            MetadataSearchCriteria ModelsSearchCriteria = new MetadataSearchCriteria();
            OperationResult ModelSearchResult;

            ModelsResultOptions.Models = ResultType.Identifiers;
            ModelsSearchCriteria.SearchOption = SearchOption.UserDefinedObjectsOnly;
            
            Metadata ModelsMetadata = service.MetadataGet(international, ModelsResultOptions, ModelsSearchCriteria, out ModelSearchResult);
            foreach (var model in ModelsMetadata.Models)
            {
                if (model.Identifier.Name == ModelName)
                    return model;
            }

            return null;
        
        }

        Entity GetEntity(Model model, string EntityName)
        {
            return GetEntity(model.Identifier, EntityName);
        }
        Entity GetEntity(Identifier modelID, string EntityName)
        {

            MetadataResultOptions EntitiesResultOptions = new MetadataResultOptions();
            MetadataSearchCriteria EntitiesSearchCriteria = new MetadataSearchCriteria();
            OperationResult EntitiesSearchResult;

            Identifier[] i;
            i = new Identifier[1];

            EntitiesResultOptions.Entities = ResultType.Identifiers;
            EntitiesSearchCriteria.SearchOption = SearchOption.BothUserDefinedAndSystemObjects;

            Metadata EntitiesMetadata = new Metadata();

            i.SetValue(modelID, 0);
            EntitiesSearchCriteria.Models = i;

            EntitiesMetadata = service.MetadataGet(international, EntitiesResultOptions, EntitiesSearchCriteria, out EntitiesSearchResult);

            foreach (var Entity in EntitiesMetadata.Entities)
            {
                if (Entity.Identifier.Name == EntityName)
                    return Entity;
            }

            return null;

        }

        
        Metadata GetEntityMetadata(Identifier EntityID)
        {

            MetadataResultOptions EntitiesResultOptions = new MetadataResultOptions();
            MetadataSearchCriteria EntitiesSearchCriteria = new MetadataSearchCriteria();
            OperationResult EntitiesSearchResult;

            Identifier[] i;
            i = new Identifier[1];

            EntitiesResultOptions.Entities = ResultType.Details;
            EntitiesSearchCriteria.SearchOption = SearchOption.BothUserDefinedAndSystemObjects;

            Metadata EntitiesMetadata = new Metadata();

            i.SetValue(EntityID, 0);
            EntitiesSearchCriteria.Entities = i;

            return service.MetadataGet(international, EntitiesResultOptions, EntitiesSearchCriteria, out EntitiesSearchResult);;

        }

      



        void ListEntities(Model model)
        {
            MetadataResultOptions EntitiesResultOptions = new MetadataResultOptions();
            MetadataSearchCriteria EntitiesSearchCriteria = new MetadataSearchCriteria();
            OperationResult EntitiesSearchResult;
            
            Identifier[] i;
            i = new Identifier[1];

            EntitiesResultOptions.Entities = ResultType.Identifiers;
            EntitiesSearchCriteria.SearchOption = SearchOption.BothUserDefinedAndSystemObjects;

            Metadata EntitiesMetadata = new Metadata();

            i.SetValue(model.Identifier, 0);
            EntitiesSearchCriteria.Models = i;

            EntitiesMetadata = service.MetadataGet(international, EntitiesResultOptions, EntitiesSearchCriteria, out EntitiesSearchResult);

            Console.WriteLine("Model {0} has {1} entities:", model.Identifier.Name, model.Entities.Count().ToString());
            foreach (var entity in EntitiesMetadata.Entities)
            {
                Console.WriteLine("Entity Code: {0}, Name: {1}", entity.Identifier.Id, entity.Identifier.Name);

            }
        
        }

        public void ListModelsAndEntities()
        {
            MetadataResultOptions ModelsResultOptions = new MetadataResultOptions();
            MetadataSearchCriteria ModelsSearchCriteria = new MetadataSearchCriteria();
            MetadataResultOptions EntitiesResultOptions = new MetadataResultOptions();
            MetadataSearchCriteria EntitiesSearchCriteria = new MetadataSearchCriteria();
            OperationResult ModelSearchResult;
            OperationResult EntitiesSearchResult;
            Identifier[] i;
            i = new Identifier[1];

            ModelsResultOptions.Models = ResultType.Identifiers;
            ModelsSearchCriteria.SearchOption = SearchOption.BothUserDefinedAndSystemObjects;

            EntitiesResultOptions.Entities = ResultType.Identifiers;
            EntitiesSearchCriteria.SearchOption = SearchOption.BothUserDefinedAndSystemObjects;

            Metadata ModelsMetadata = service.MetadataGet(international, ModelsResultOptions, ModelsSearchCriteria, out ModelSearchResult);
            Metadata EntitiesMetadata = new Metadata();

            foreach (var model in ModelsMetadata.Models)
            {
                Console.WriteLine("Model Code: {0}, Name: {1}", model.Identifier.Id, model.Identifier.Name);

                i.SetValue(model.Identifier, 0);
                EntitiesSearchCriteria.Models = i;

                EntitiesMetadata = service.MetadataGet(international, EntitiesResultOptions, EntitiesSearchCriteria, out EntitiesSearchResult);

                foreach (var entity in EntitiesMetadata.Entities)
                {
                    //Console.WriteLine("Entity Code: {0}, Name: {1}", entity.Identifier.Id, entity.Identifier.Name);

                }

            }
            
        }

    }
}
